#include <windows.h>
#include <d2d1.h>
#include <mutex>
#include <atomic>

#include <stdio.h>
#include <conio.h>
#include <thread>
#include <chrono>
#include <vector>
#include "parsec-vdd.h"

#pragma comment(lib, "d2d1.lib")
#pragma comment(lib, "user32.lib")

#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p) = NULL; } }


using namespace std::chrono_literals;
using namespace parsec_vdd;


namespace {
    std::mutex g_animMutex;
    std::vector<DisplayAnimation> g_animations;
    std::atomic<bool> g_globalRunning(false);
}

// Direct2D动画线程函数
DWORD WINAPI AnimationThread(LPVOID lpParam) {
    DisplayAnimation* anim = static_cast<DisplayAnimation*>(lpParam);
    
    // 注册窗口类
    WNDCLASSEX wc = { sizeof(WNDCLASSEX) };
    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = DefWindowProc;
    wc.hInstance = GetModuleHandle(NULL);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.lpszClassName = "ParsecAnimClass";
    RegisterClassEx(&wc);

    // 创建透明窗口
    HWND hWnd = CreateWindowEx(
        WS_EX_LAYERED | WS_EX_TRANSPARENT | WS_EX_TOPMOST,
        "ParsecAnimClass", "",
        WS_POPUP,
        anim->rect.left,
        anim->rect.top,
        anim->rect.right - anim->rect.left,
        anim->rect.bottom - anim->rect.top,
        NULL, NULL, NULL, NULL);

    SetLayeredWindowAttributes(hWnd, 0, 1, LWA_ALPHA);
    ShowWindow(hWnd, SW_SHOW);

    // 初始化Direct2D
    ID2D1Factory* pFactory = NULL;
    ID2D1HwndRenderTarget* pRT = NULL;
    ID2D1SolidColorBrush* pBrush = NULL;
    
    D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &pFactory);
    
    if (pFactory) {
        D2D1_SIZE_U size = D2D1::SizeU(
            anim->rect.right - anim->rect.left,
            anim->rect.bottom - anim->rect.top);
        
        pFactory->CreateHwndRenderTarget(
            D2D1::RenderTargetProperties(),
            D2D1::HwndRenderTargetProperties(hWnd, size),
            &pRT);
        
        if (pRT) {
            pRT->CreateSolidColorBrush(
                D2D1::ColorF(D2D1::ColorF::White), &pBrush);
        }
    }

    // 动画循环
    float pos = 0.0f;
    const float speed = 2.0f;
    const float height = static_cast<float>(anim->rect.bottom - anim->rect.top);
    
    while (anim->active) {
        if (pRT && pBrush) {
            pRT->BeginDraw();
            pRT->Clear(D2D1::ColorF(0, 0, 0, 0));
            
            // 绘制移动线
            D2D1_RECT_F rect = D2D1::RectF(
                0, pos,
                static_cast<float>(anim->rect.right - anim->rect.left),
                pos + 2.0f);
            pRT->FillRectangle(rect, pBrush);
            
            pos += speed;
            if (pos > height) pos = 0;
            
            pRT->EndDraw();
        }
        Sleep(41); // ~25Hz, default 8, ~120Hz
    }

    // 清理资源
    SAFE_RELEASE(pBrush);
    SAFE_RELEASE(pRT);
    SAFE_RELEASE(pFactory);
    DestroyWindow(hWnd);
    delete anim;
    
    return 0;
}

BOOL parsec_vdd::StartDisplayAnimation(int index, const RECT& rect) {
    std::lock_guard<std::mutex> lock(g_animMutex);

    // 检查是否已存在
    for (const auto& anim : g_animations) {
        if (anim.index == index) return FALSE;
    }

    // 创建动画信息
    DisplayAnimation* newAnim = new DisplayAnimation;
    newAnim->index = index;
    newAnim->active = true;
    newAnim->rect = rect;

    // 启动线程
    newAnim->hThread = CreateThread(
        NULL, 0, AnimationThread, newAnim, 0, NULL);
    
    if (newAnim->hThread) {
        g_animations.push_back(*newAnim);
        return TRUE;
    }
    return FALSE;
}

void parsec_vdd::StopDisplayAnimation(int index) {
    std::lock_guard<std::mutex> lock(g_animMutex);

    for (auto it = g_animations.begin(); it != g_animations.end(); ++it) {
        if (it->index == index) {
            it->active = false;
            WaitForSingleObject(it->hThread, 1000);
            CloseHandle(it->hThread);
            g_animations.erase(it);
            break;
        }
    }
}


int main(int argc,char *argv[])
{
    // Check driver status.
    DeviceStatus status = QueryDeviceStatus(&VDD_CLASS_GUID, VDD_HARDWARE_ID);
    if (status != DEVICE_OK)
    {
        printf("Parsec VDD device is not OK, got status %d.\n", status);
        return 1;
    }

    // Obtain device handle.
    HANDLE vdd = OpenDeviceHandle(&VDD_ADAPTER_GUID);
    if (vdd == NULL || vdd == INVALID_HANDLE_VALUE) {
        printf("Failed to obtain the device handle.\n");
        return 1;
    }

    bool running = true;
    std::vector<int> displays;
    g_globalRunning = true;

    // Side thread for updating vdd.
    std::thread updater([&running, vdd] {
        while (running) {
            VddUpdate(vdd);
            std::this_thread::sleep_for(100ms);
        }
    });

    updater.detach();

    // Print out guide.
    printf("parsec-vdd-cli.exe [-a]\n");
    printf("  -a add a virtual display at startup.\n");
    printf("\n");

    printf("Press A to add a virtual display.\n");
    printf("Press R to remove the last added.\n");
    printf("Press Q to quit (then unplug all).\n\n");

    if (running) {
        if (argc == 2 && strcmp(argv[1], "-a") == 0 ) {
            if (displays.size() < VDD_MAX_DISPLAYS) {
                int index = VddAddDisplay(vdd);
                displays.push_back(index);
                printf("Added a new virtual display, index: %d.\n", index);
            }
            else {
                printf("Limit exceeded (%d), could not add more virtual displays.\n", VDD_MAX_DISPLAYS);
            }
        }
    }

    // 修改后的用户交互循环
    while (running) {
        switch (_getch()) {
			// quit
            case 'q':
                running = false;
                break;
            // add display
        case 'a': {
            if (displays.size() >= VDD_MAX_DISPLAYS) {
                printf("Maximum displays reached\n");
                break;
            }

            int index = VddAddDisplay(vdd);
            if (index != -1) {
                displays.push_back(index);
                printf("Added display #%d\n", index);

                // 获取显示器信息
                DISPLAY_DEVICE dd = { sizeof(DISPLAY_DEVICE) };
                DEVMODE dm = { 0 };
                for (int i = 0; EnumDisplayDevices(NULL, i, &dd, 0); ++i) {
                    if (strstr(dd.DeviceID, VDD_DISPLAY_ID) && 
                        EnumDisplaySettings(dd.DeviceName, ENUM_CURRENT_SETTINGS, &dm)) 
                    {
                        RECT rect = {
                            dm.dmPosition.x,
                            dm.dmPosition.y,
                            dm.dmPosition.x + dm.dmPelsWidth,
                            dm.dmPosition.y + dm.dmPelsHeight
                        };
                        StartDisplayAnimation(index, rect);
                        break;
                    }
                }
            }
            break;
        }
		 // remove display
        case 'r': {
            if (!displays.empty()) {
                int index = displays.back();
                StopDisplayAnimation(index);
                VddRemoveDisplay(vdd, index);
                displays.pop_back();
                printf("Removed display #%d\n", index);
            }
            break;
        }
        // ... [其他case保持不变] ...
        }
    }

    // 退出时清理
    for (int index : displays) {
        StopDisplayAnimation(index);
        VddRemoveDisplay(vdd, index);
    }


#if 0
    while (running) {
        switch (_getch()) {
            // quit
            case 'q':
                running = false;
                break;
            // add display
            case 'a':
                if (displays.size() < VDD_MAX_DISPLAYS) {
                    int index = VddAddDisplay(vdd);
                    displays.push_back(index);
                    printf("Added a new virtual display, index: %d.\n", index);
                }
                else {
                    printf("Limit exceeded (%d), could not add more virtual displays.\n", VDD_MAX_DISPLAYS);
                }
                break;
            // remove display
            case 'r':
                if (displays.size() > 0) {
                    int index = displays.back();
                    VddRemoveDisplay(vdd, index);
                    displays.pop_back();
                    printf("Removed the last virtual display, index: %d.\n", index);
                }
                else {
                    printf("No added virtual displays.\n");
                }
                break;
        }
    }

    // Remove all before exiting.
    for (int index : displays) {
        VddRemoveDisplay(vdd, index);
    }
# endif

    if (updater.joinable()) {
        updater.join();
    }

    // Close the device handle.
    CloseDeviceHandle(vdd);

    return 0;
}